#include <jni.h>
#include <stdio.h>
#include "extmodule_ExtProposalMC.h"
#include "random_Opp.h"
#include <vector>
#include <iostream>

using namespace std;

Random_Opp *player;

JNIEXPORT jboolean JNICALL Java_extmodule_ExtProposalMC_init(JNIEnv *env, jobject obj) {

      printf("MC: init():\n");

	srand ( time(NULL) ); 

	player = new Random_Opp();

//	player->setChips(23);
//	cout << "chips: " << player->chips << "\n";

//      cout << "\n";
        return true;
}

JNIEXPORT void JNICALL Java_extmodule_ExtProposalMC_setChips(JNIEnv *env, jobject obj, jint in_cash) {

//      printf("MC: setChips():\n");

	player->setChips(in_cash);
	
//	cout << "chips: " << player->chips << "\n";

//	cout << "\n";
	return;
}

JNIEXPORT void JNICALL Java_extmodule_ExtProposalMC_setCards(JNIEnv *env, jobject obj, jint card1, jint card2) {

//        printf("MC: setCards():\n");

	Card c1 = Card(card1);
	Card c2 = Card(card2);

	HoleCards holeCards = HoleCards(c1, c2);

	player->setHoleCards(holeCards);

//	cout << "card1: " << c1.getName() << " " << c1.getValue() << "\n";

//	cout << "card2: " << c2.getName() << " " << c2.getValue() << "\n";


	int i = player->holeCards.cards[0].getValue();
//	cout << "hole cards: " << player->holeCards.getName() << "\n";

//        cout << "\n";
	return;
}

JNIEXPORT void JNICALL Java_extmodule_ExtProposalMC_showResult(JNIEnv *env, jobject obj, jboolean dealer, jint card1, jint card2) {

//        printf("MC: showResult():\n");

	vector<Action> actions = getActions(env, obj);

        vector<Card> boardCards = getBoardCards(env, obj);

	Card c1 = Card(card1);
        Card c2 = Card(card2);

        HoleCards holeCards = HoleCards(c1, c2);

//	cout << "actions.size(): " << actions.size() << "\n";
//	cout << "action 0: " << actions.at(0).move;
//	cout << "action 1: " << actions.at(1).move;

	player->showResult(&actions, boardCards, dealer, holeCards); // TODO replace 0 with value of boardSize

//        cout << "\n";
	return;
}

JNIEXPORT jint JNICALL Java_extmodule_ExtProposalMC_getNextAction(JNIEnv *env, jobject obj, jint player2_chips, jboolean dealer) {

//        printf("MC: getNextAction():\n");

	vector<Action> actions = getActions(env, obj);

        vector<Card> cards = getBoardCards(env, obj);

	//Action proposal = player->getNextAction(actions, cards, player2_chips);
        Action proposal = player->getNextAction(actions, cards, player->chips, player2_chips, dealer);


	int result = -11;

	if(proposal.move == fold) {

//		cout << "proposal: fold\n";
		result = -1;

	} else if (proposal.move == check) {

//		cout << "proposal: check\n";
		result = 0;

        } else if (proposal.move == call) {

//		cout << "proposal: call\n";
		result = 1;

        } else if (proposal.move == raise) {

//		cout << "proposal: raise\n";
		result = 2;
	}

	return result; // TODO return move and value somehow (maybe object[] ?)
}

vector<Action> getActions(JNIEnv *env, jobject obj) {

	vector<Action> actions = vector<Action>();

        jclass jcls = (*env).GetObjectClass(obj);
        jmethodID sizeID = (*env).GetMethodID(jcls, "getNumActions", "()I");

        jmethodID getOptionID = (*env).GetMethodID(jcls, "getOption", "(I)C");
        jmethodID getValueID = (*env).GetMethodID(jcls, "getValue", "(I)I");


        int numActions = (*env).CallIntMethod(obj, sizeID);


        for( int i = 0; i < numActions; i++ ) {

                char optionChar = (*env).CallCharMethod(obj, getOptionID, i);
                int value = (*env).CallCharMethod(obj, getValueID, i);
//                cout << "action " << i << ": " << optionChar << value << "\n";

                if( optionChar == 'b' ) {

                        actions.push_back(Action(postBlind, value));

                } else if( optionChar == 'f' ) {

                        actions.push_back(Action(fold, value));

                } else if( optionChar == 'c' ) {

                        actions.push_back(Action(check, value));

                } else if( optionChar == 'C' ) {

                        actions.push_back(Action(call, value));

                } else if( optionChar == 'r' ) {

                        actions.push_back(Action(raise, value));

                } else {

                        // TODO fallback?
                }
	}

	return actions;
}

vector<Card> getBoardCards(JNIEnv *env, jobject obj) {

	vector<Card> cards = vector<Card>();

        jclass jcls = (*env).GetObjectClass(obj);
        jmethodID sizeID = (*env).GetMethodID(jcls, "getNumBoardCards", "()I");

        jmethodID getCardID = (*env).GetMethodID(jcls, "getBoardCard", "(I)I");

        int numCards = (*env).CallIntMethod(obj, sizeID);

        for( int i = 0; i < numCards; i++ ) {

                int value = (*env).CallCharMethod(obj, getCardID, i);
//              cout << "card " << i << ": " << value << "\n";
		cards.push_back(Card(value));
	}
        
	return cards;
}


